摘要:2026 年 10 月公开的 CVE-2026-99999(代号 PwnEscape)是一个位于 宿主机 Linux 网络栈 的 guest-to-host 逃逸漏洞,对任何运行多租户 KVM 的环境都构成直接威胁。本文记录一台 Debian 13 节点从"确认受影响"到"升级内核并重启验收"的完整过程,包含全部命令与真实回显,并给出多节点推广、回滚预案与长期治理方案。
1. 漏洞背景
1.1 一句话概括
漏洞不在 KVM 里,而在宿主机 Linux 的 IPv4 校验和补全路径:客户机可以提交伪造的 virtio 校验和元数据,使内核在已经校验过 IPv4 头之后再向报文写入 2 字节,从而把 IPv4 首字节从 0x45(IHL=5,20 字节头)改成 0x4f(IHL=15,60 字节头)。随后输出分片(ip_do_fragment())按 60 字节复制"头部",把超出报文逻辑长度的 32 字节宿主内存当作 IP options 发了出去。
1.2 利用链
不可信输入(guest) 宿主机网络栈
───────────────────── ─────────────────────────────
报文 + CHECKSUM_PARTIAL 元数据 ───────► 卸载元数据写入 skb
│
▼
链路层剥离 / L3 规范化
│
▼
IPv4 解析、重组、策略、路由
(此时信任 IHL=5 / 20 字节)
│
▼
输出分片
│
▼
skb_checksum_help()
(延迟写入覆盖了已被解析的头)
│
▼
ip_do_fragment() 读取晚到的 IHL
头部现在声称 60 字节
│
▼
头部拷贝超出逻辑线性数据
│
▼
发出的 IP options 里含宿主内存三个关键认知:
skb->csum_start/csum_offset不是描述性元数据,而是一次写入授权:写入位置 =csum_start + csum_offset。- 校验发生在解析时,写入发生在分片时。两者之间头已经被信任过一次,属于语义上的 TOCTOU(时间差完全确定,不依赖线程竞争)。
- 32 字节泄露只是第一步。研究者用宿主内存观测 + 堆布局控制,在自有实验机上实现了受控的 64 字节内核写,并在四次冷启动中复现了"执行宿主 root helper 并回传标记"的完整链路。
1.3 影响面与时间线
| 项目 | 内容 |
|---|---|
| CVE | CVE-2026-99999 |
| 类型 | 宿主内存泄露 → 内核写 → guest-to-host 逃逸 |
| 受影响范围 | 使用 virtio-net 校验和卸载路径的 Linux KVM 宿主机(默认配置即在影响面内);TUN / AF_PACKET 场景同样触及 |
| 上游修复 | 6785011f8b16,提交标题 ipv4: validate checksum_start before completing checksum |
| 上游节奏 | 2026-10-08 进入 net.git,2026-10-14 合入主线 |
| 公开披露 | 2026-10-15(oss-security) |
| 研究者预期 | "较弱配置的利用数周内出现,默认配置的利用一个月内出现" |
修复本身是一个纵深防御性质的守卫(官方提交信息明确如此描述),更完整的入站侧校验仍在推进。也就是说:打完这个补丁不等于终点,后续还会有跟进的内核更新。
1.4 Debian 的修复状态
| 发行版 | 版本 | 状态 |
|---|---|---|
| trixie(Debian 13)security | 6.12.113-1 | ✅ 已修复(DSA-6568-1) |
| trixie(发布源) | 6.12.107-1 | ❌ 受影响 |
| bookworm(Debian 12)security | 6.1.187-1 | ❌ 仍受影响,暂无修复 |
| sid | 7.2.11-1 | ✅ 已修复 |
结论:Debian 13 已有官方修复版;Debian 12 目前没有。 这一步决定了整改路线——Debian 13 节点一条 apt 命令即可修完,Debian 12 节点则只能先缩小暴露面。
1.5 为什么这类漏洞不能等
- 我们是多租户 KVM 宿主,客户机本身就是"不可信 guest",与漏洞前提完全一致;
- 逃逸成功后,同一宿主机上的所有客户机、以及宿主机上的所有凭据全部沦陷;
- 上游定性为纵深防御,后续还有补丁 → 这意味着"等一个更完整的修复"是错误策略,应当立即跟进。
2. 确认自己是否受影响
root@debian:~# uname -r
6.12.73+deb13-amd64| 当前内核 | 判定 |
|---|---|
< 6.12.113 | 受影响,需升级 |
>= 6.12.113 | 已包含修复 |
本机为 6.12.73 → 受影响。
3. 修复路线选型
| 路线 | 可行性 | 结论 |
|---|---|---|
发行版安全源(trixie-security) | 已提供 6.12.113-1 | 采用。一条命令、有签名、可回滚、后续可持续跟进 |
| backports | 修复版已进安全源,无必要 | 不采用 |
| 自行编译 / 手工打补丁 | 破坏包管理与签名链,后续升级会打架 | 不采用 |
| 内核热补丁(livepatch / kpatch / kGraft) | Debian 无官方支持 | 不采用,必须重启 |
4. 升级前的三个检查
4.1 确认 apt 源包含 trixie-security
Debian 13 使用 deb822 格式:
root@debian:~# cat /etc/apt/sources.list.d/*.sources
Types: deb
URIs: http://deb.debian.org/debian
Suites: trixie trixie-updates
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: http://security.debian.org/debian-security
Suites: trixie-security
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg修复版只存在于 trixie-security,源里没有它,后面无论怎么 apt 都拿不到补丁。
4.2 确认候选版本(核心判据)
root@debian:~# apt-get update
Hit:1 http://security.debian.org/debian-security trixie-security InRelease
Hit:2 http://deb.debian.org/debian trixie InRelease
Get:3 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB]
Fetched 47.3 kB in 0s (235 kB/s)
Reading package lists... Done
root@debian:~# apt-cache policy linux-image-amd64
linux-image-amd64:
Installed: 6.12.73-1
Candidate: 6.12.113-1
Version table:
6.12.113-1 500
500 http://security.debian.org/debian-security trixie-security/main amd64 Packages
6.12.107-1 500
500 http://deb.debian.org/debian trixie/main amd64 Packages
*** 6.12.73-1 100
100 /var/lib/dpkg/status判据:Candidate 必须 ≥ 6.12.113-1。
顺带说明两个容易被忽略的点:
trixie-security与主源优先级同为 500,apt 取版本号最高的那个,因此6.12.113-1会胜过6.12.107-1;- 若
Candidate仍是 73 或 107,说明镜像源未同步或安全源未生效——此时不要装,先对照 DSA-6568-1 排查,否则会"装了个新内核但其实没修"。
4.3 干跑,确认不会移除任何包
root@debian:~# apt-get --dry-run install linux-image-amd64
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
linux-image-6.12.113+deb13-amd64
Suggested packages:
firmware-linux-free linux-doc-6.12 debian-kernel-handbook
The following NEW packages will be installed:
linux-image-6.12.113+deb13-amd64
The following packages will be upgraded:
linux-image-amd64
1 upgraded, 1 newly installed, 0 to remove and 80 not upgraded.
Inst linux-image-6.12.113+deb13-amd64 (6.12.113-1 Debian-Security:13/stable-security [amd64])
Inst linux-image-amd64 [6.12.73-1] (6.12.113-1 Debian-Security:13/stable-security [amd64])
Conf linux-image-6.12.113+deb13-amd64 (6.12.113-1 Debian-Security:13/stable-security [amd64])
Conf linux-image-amd64 (6.12.113-1 Debian-Security:13/stable-security [amd64])三个要点:
0 to remove—— 没有任何删除动作,说明不会动到 libvirt / QEMU 等依赖;- 来源标注为
Debian-Security:13/stable-security—— 确认装的是安全源版本,而不是发布源里的旧版; 80 not upgraded—— 这是正确的结果。本机还有 80 个包可升级,但那与本次修复无关;宿主机上的 libvirt / QEMU 升级需要单独评估窗口,不应顺手带过。
5. 执行升级
5.1 安装命令,以及两个"不要"
apt-get install -y linux-image-amd64❌ 不要加
--only-upgrade:新内核是一个新包(linux-image-6.12.113+deb13-amd64),--only-upgrade禁止安装新包,会直接因依赖不满足而失败。❌ 不要用
apt full-upgrade:那会连同 libvirt、QEMU 一起升级。宿主机上这两个组件的变更必须单独做评估与回归,不能掩盖在一次内核升级里。
5.2 真实安装输出解读
root@debian:~# apt-get install -y linux-image-amd64
Need to get 108 MB of archives.
After this operation, 111 MB of additional disk space will be used.
Get:1 http://security.debian.org/debian-security trixie-security/main amd64 linux-image-6.12.113+deb13-amd64 amd64 6.12.113-1 [108 MB]
Get:2 http://security.debian.org/debian-security trixie-security/main amd64 linux-image-amd64 amd64 6.12.113-1 [1,480 B]
Fetched 108 MB in 2s (60.1 MB/s)
...
Setting up linux-image-6.12.113+deb13-amd64 (6.12.113-1) ...
I: /vmlinuz is now a symlink to boot/vmlinuz-6.12.113+deb13-amd64
I: /initrd.img is now a symlink to boot/initrd.img-6.12.113+deb13-amd64
/etc/kernel/postinst.d/initramfs-tools:
update-initramfs: Generating /boot/initrd.img-6.12.113+deb13-amd64
/etc/kernel/postinst.d/zz-update-grub:
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.12.113+deb13-amd64
Found initrd image: /boot/initrd.img-6.12.113+deb13-amd64
Found linux image: /boot/vmlinuz-6.12.73+deb13-amd64
Found initrd image: /boot/initrd.img-6.12.73+deb13-amd64
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding boot menu entry for UEFI Firmware Settings ...
done
Setting up linux-image-amd64 (6.12.113-1) ...四个关键信息:
initramfs已重新生成,没有它就起不来;- GRUB 同时找到新内核与旧内核(
113与73)→ 回滚路径存在,这是判断本次操作是否"可逆"的核心依据; /vmlinuz、/initrd.img软链已切到新内核;os-prober那条 warning 在单系统盘上是正常提示,可忽略。
5.3 重启前验证
root@debian:~# dpkg-query -W -f='${Version}\n' linux-image-amd64
6.12.113-1
root@debian:~# ls -1 /boot/vmlinuz-*
/boot/vmlinuz-6.12.113+deb13-amd64
/boot/vmlinuz-6.12.73+deb13-amd64
root@debian:~# df -h /boot
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 944M 114M 765M 13% /boot另外建议立刻把旧内核标记为手动安装,防止日后 apt autoremove 清理掉回滚路:
apt-mark manual linux-image-6.12.73+deb13-amd64以及一条运维常识:/boot 独立分区只有 944M,一套内核(image + initrd)约 60M,装三四个没问题;但要定期 apt autoremove --purge,/boot 塞满会导致下一次内核安装直接失败。
6. 重启与验收
6.1 确认新内核已启动
root@debian:~# uname -r
6.12.113+deb13-amd64登录横幅同样能确认:
Linux debian 6.12.113+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.113-1 (2026-10-15) x86_646.2 网络与 DNS 的持久化验证
内核升级必然伴随重启,重启暴露出来的问题往往不是内核,而是网络配置是否持久。先在重启前确认"谁在管网络":
root@debian:~# systemctl is-enabled networking systemd-networkd NetworkManager
enabled
disabled
not-found
root@debian:~# systemctl is-active networking systemd-networkd NetworkManager
active
inactive
inactive
root@debian:~# cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
auto ens1f0np0
iface ens1f0np0 inet static
address 198.51.100.10/24
gateway 198.51.100.1root@debian:~# systemctl is-enabled cloud-init
not-found| 组合 | 含义 | 重启风险 |
|---|---|---|
networking active + interfaces 里是 inet static | ifupdown 静态配置 | 无,原样恢复 |
interfaces 里是 inet dhcp | 地址由 DHCP 下发 | 可能变 IP,需确认保留绑定 |
systemd-networkd / NetworkManager 接管 | 看对应目录下的配置 | 取决于配置 |
cloud-init 存在 | 开机可能重写网络 | 需要单独确认 |
本机结论:ifupdown + 静态地址 + 无 cloud-init → 重启后网络原样恢复。
一个容易被忽略的坑:DNS
interfaces 里只有 address 和 gateway,没有 dns-nameservers。若 /etc/resolv.conf 是由 resolvconf 在启动时根据 interfaces 重新生成的,重启后它会是空的——表现为 ping 1.1.1.1 通、ping deb.debian.org 不通、apt 直接报错。
重启前先查:
ls -l /etc/resolv.conf
cat /etc/resolv.conf- 普通文件且写着
nameserver→ 不会被动,无需处理; - 软链(指向
/run/resolvconf/...或 systemd-resolved 的 stub)→ 会被重生成,在interfaces里补一行:
dns-nameservers 1.1.1.1 8.8.8.8改完用 ifquery ens1f0np0 校验语法(不要用 systemctl restart networking 去应用,重启会自己生效)。
6.3 重启前后对照
重启前留档,重启后逐项对比——这是验证持久化最省事的办法:
ip -br a > /root/pre-reboot-net.txt
ip route >> /root/pre-reboot-net.txt
cat /etc/resolv.conf >> /root/pre-reboot-net.txt重启后:
diff <(ip -br a; ip route) /root/pre-reboot-net.txt && echo "网络配置完全一致"
cat /etc/resolv.conf
uname -r
systemctl --failed
ping -c2 1.1.1.1 && ping -c2 deb.debian.org
dmesg --level=err,warn | tail -206.4 验收判定表
| 检查项 | 通过标准 |
|---|---|
| 内核 | uname -r = 6.12.113+deb13-amd64 |
| 回滚路 | /boot 中旧内核仍在 |
| 网络 | diff 无输出,IP / 路由 / DNS 一致 |
| 系统 | systemctl --failed 为空 |
| 外网 | ICMP 与 DNS 解析都通 |
| 硬件 | dmesg 无新增 nvme / 网卡 error |
7. 如何验证补丁"真的生效":两个错误做法与一个正确做法
这一节值得单独写,因为很容易得出错误结论。
❌ 错误做法一:在 Debian 内核 changelog 里 grep 提交主题
zcat /usr/share/doc/linux-image-*/changelog.Debian.gz | grep -i checksum_start # 无输出Debian 内核包的 changelog.Debian.gz 只记录发布层面的变更(如 "Rebase to 6.12.113"、DSA 编号),不记录上游逐条提交的主题。查不到不代表补丁没进。
❌ 错误做法二:在 System.map 里找 ip_check_csum_start
grep -c ip_check_csum_start /boot/System.map-6.12.113+deb13-amd64 # 0该策略函数在上游是 static inline,会被内联到调用点,编译产物里没有对应符号。用 0 来判断"没修复"是彻底误判。
✅ 正确做法:用版本号对照发行版安全跟踪器
| 判据 | 本次取值 |
|---|---|
| Debian 官方标记的修复版本(trixie) | 6.12.113-1 |
| 本机已安装版本 | 6.12.113-1 |
| 包来源 | Debian-Security:13/stable-security |
三者一致即视为已修复。这条链路同时被官方公告(DSA-6568-1)与安全跟踪器背书,比任何二进制特征扫描都可靠。
8. 推广到其它节点
8.1 分批顺序
先在无任何业务负载的节点上验证(本次即如此),确认"新内核能在这批硬件上启动"之后,再推有业务的节点。理由是:内核升级真正的风险不是软件包,而是新内核在你这个硬件平台上能不能起来、网卡与 NVMe 是否正常——空机器是零成本的探雷器。
8.2 有虚拟机的宿主机:附加步骤
# 1) 留档现状
virsh list --all
virsh net-list --all
ip -br a; ip route
findmnt /homedata; swapon --show
# 2) 优雅关机所有虚拟机
for d in $(virsh list --name); do virsh shutdown "$d"; done
watch -n2 'virsh list --all' # 等到全部 shut off 再继续关于关机必要性的说明:
- 磁盘缓存为
cache=none时,客户机数据本身是落盘的,直接重启不会损坏镜像,但优雅关机仍然是标准动作——它保证客户机文件系统干净卸载; - 若使用
cache=unsafe(忽略客户机 flush),则必须优雅关机,直接重启或断电会导致客户机文件系统乃至 qcow2 元数据损坏。
重启后除 6.3 的清单,还要复核宿主机侧服务:
virsh net-list --all # 路由型网络应为 active + autostart yes
sysctl -n net.ipv4.ip_forward # 1
systemctl is-active libvirtd vf-nginx vf-php8-fpm supervisor
ss -lntp | grep 8892 # 面板通信端口
findmnt /homedata && swapon --show8.3 网络配置经过手工改造的节点:分两次重启
如果某台节点的网络是手工改过的(例如私有 /31 传输段 + 公网 /24 三层路由 + libvirt 路由型网桥),且此前从未经历一次完整重启,那么建议:
| 步骤 | 目的 |
|---|---|
| 第 1 次:不升内核,纯重启 | 单独验证网络/存储/网桥的持久化是否成立 |
| 第 2 次:升内核后再重启 | 此时若异常,可确定是内核而非配置导致 |
两次重启之间留出观察时间。把两个变量拆开,是把"起不来"从"不可诊断"变成"可诊断"的最便宜手段。
8.4 回滚的三种手段
| 场景 | 手段 |
|---|---|
| 新内核起得来但有问题 | GRUB 里选旧内核启动,然后 apt-mark hold linux-image-amd64 钉住版本 |
| 新内核完全起不来 | 带外管理(IPMI / KVM over IP)进入 GRUB → Advanced options → 选旧内核 |
| 想预设一次性默认项 | grub-reboot "<旧内核菜单标题>",只影响下一次启动 |
前提是带外管理可用。没有带外管理的单机执行内核升级,等于把机器交给运气。
9. 临时缓解:为什么基本没有
在补丁窗口期内,常见三个"聪明办法"都不成立:
| 候选方案 | 结论 | 原因 |
|---|---|---|
关闭 virtio 网卡的 TX 校验和卸载(-global virtio-net-pci.guest_csum=off) | 不可靠 | 入站解析路径不校验特性是否协商,恶意客户机可以自行置位 NEEDS_CSUM,仍然走 CHECKSUM_PARTIAL |
| 改用 e1000 / vmxnet3 等网卡模型 | 无效 | 这些模型同样具备校验和卸载能力,且性能更差 |
| 限制客户机 MTU、减少宿主分片 | 仅降低概率 | 客户机可自行构造超过宿主 MTU 的帧,绕过自身协议栈约束 |
唯一正解是升级内核。 窗口期内能做的只有缩小爆炸半径:
- 面板通信端口(
8892)只允许控制端 IP 访问,SSH 限制来源; - 宿主机保持最小化,除虚拟化管理套件外不安装其它服务;
- 在补丁完成前,不向不可信租户开放新的多租户实例。
10. 长期:把内核升级做成 SOP
一个逃逸级漏洞必然有下一个。把本次流程固化下来,比记住某一次的命令更有价值。
10.1 只自动下载,不自动重启
apt-get install -y unattended-upgrades apt-listchanges
dpkg-reconfigure -plow unattended-upgrades确认 /etc/apt/apt.conf.d/50unattended-upgrades 中:
Unattended-Upgrade::Automatic-Reboot "false";宿主机必须人工把住重启窗口(要优雅关机所有虚拟机),自动重启是事故制造机。
10.2 订阅源
- Debian 安全公告(DSA):https://www.debian.org/security/
- 安全跟踪器:https://security-tracker.debian.org/tracker/CVE-2026-99999
10.3 标准作业流程
| 步骤 | 动作 | 判据 |
|---|---|---|
| 1 | 查安全跟踪器,确认修复版本 | 得到形如 6.12.113-1 的目标版本 |
| 2 | apt-get update + apt-cache policy linux-image-amd64 | Candidate ≥ 修复版本 |
| 3 | apt-get --dry-run install linux-image-amd64 | 无 Remv,来源为 security |
| 4 | 优雅关机所有虚拟机 | virsh list --all 全部 shut off |
| 5 | apt-get install -y linux-image-amd64 | 无报错,initramfs 与 grub 正常生成 |
| 6 | reboot | — |
| 7 | 验收清单 | 内核版本、systemctl --failed、网络、8892、存储、虚拟机自启 |
10.4 心态
本次修复被上游明确描述为纵深防御,完整的入站侧校验仍在推进。这意味着 6.12.113 修掉的是已知的这一条利用链,而不是这一类问题的全部。把内核升级当作常规动作,而不是一次性事件。
11. 经验清单
必须做
- 升级前确认
Candidate≥ 官方标记的修复版本,来源必须是 security 源; - 干跑确认
0 to remove,不用full-upgrade夹带其它组件升级; - 确认
/boot里旧内核仍在(回滚路),并apt-mark manual防止被autoremove清掉; - 有带外管理再动内核升级;
- 有虚拟机的宿主机,重启前优雅关机所有虚拟机;
- 重启前留档网络状态,重启后
diff比对; - 检查
interfaces是否缺dns-nameservers(重启后 DNS 丢失的经典原因)。
禁止做
- 用
grep changelog或grep System.map判断补丁是否生效; - 加
--only-upgrade装内核(会因依赖不满足失败); - 在宿主机上
apt full-upgrade(libvirt/QEMU 变更需要单独窗口); - 无带外管理、有虚拟机在跑的情况下直接重启;
- 把"打完这个补丁"当作该类问题的终点。
附录 A:命令速查
# 判断是否受影响
uname -r
# 确认源与候选版本
cat /etc/apt/sources.list.d/*.sources
apt-get update && apt-cache policy linux-image-amd64
# 干跑(判据:0 to remove,来源为 security)
apt-get --dry-run install linux-image-amd64
# 安装(不加 --only-upgrade,不用 full-upgrade)
apt-get install -y linux-image-amd64
# 重启前确认
dpkg-query -W -f='${Version}\n' linux-image-amd64
ls -1 /boot/vmlinuz-*
df -h /boot
apt-mark manual linux-image-6.12.73+deb13-amd64
# 重启前留档
ip -br a > /root/pre-reboot-net.txt; ip route >> /root/pre-reboot-net.txt
# 重启后验收
uname -r
diff <(ip -br a; ip route) /root/pre-reboot-net.txt && echo "网络配置完全一致"
systemctl --failed
ping -c2 1.1.1.1 && ping -c2 deb.debian.org
dmesg --level=err,warn | tail -20附录 B:参考资料
- 研究者披露原文:https://pwn.ai/blog/pwnescape
- oss-security 通告:https://www.openwall.com/lists/oss-security/2026/10/15/5
- 上游修复提交
6785011f8b16:https://github.com/torvalds/linux/commit/6785011f8b16abf40b1e9d8b2e332232b3e68822 - Debian 安全跟踪器 CVE-2026-99999:https://security-tracker.debian.org/tracker/CVE-2026-99999
- Debian 安全公告 DSA-6568-1:https://security-tracker.debian.org/tracker/DSA-6568-1
- Linux 校验和卸载文档:https://docs.kernel.org/networking/checksum-offloads.html
暂无评论
还没有评论,来说点什么吧